package com.money.tracker.generator.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.money.tracker.common.constant.MoneyTrackerConstant;
import com.money.tracker.common.utils.StreamUtil;
import com.money.tracker.generator.constant.GenConstants;
import com.money.tracker.generator.entity.GenTable;
import com.money.tracker.generator.entity.GenTableColumn;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.util.*;


/**
 * <p>
 * 模版引擎工具类
 * </p>
 *
 *
 * @author zhangshuai
 * @date 2024/12/06
 */

@Component
@Slf4j
public class VelocityHelper {

    /**
     * 渲染的模版
     */
    private static final List<String> TEMPLATES = Arrays.asList(
            "vm/java/entity/req/req.java.vm",
            "vm/java/entity/rsp/rsp.java.vm",
            "vm/java/entity/entity.java.vm",
            "vm/java/mapper/mapper.java.vm",
            "vm/java/service/service.java.vm",
            "vm/java/service/serviceImpl.java.vm",
            "vm/java/controller/controller.java.vm",
            "vm/java/mapper/mapper.xml.vm",
            "vm/js/api.js.vm",
            "vm/vue/index.vue.vm"
    );


    @PostConstruct
    public void initVelocity() {
        Properties p = new Properties();

        // 加载classpath目录下的vm文件
        p.setProperty(Velocity.RESOURCE_LOADERS, "class");
        // 定义字符集
        p.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        // 初始化Velocity引擎，指定配置Properties
        Velocity.init(p);
    }

    /**
     * 获取模板信息
     *
     * @return 模板列表
     */
    public List<String> getTemplateList(String tplCategory) {
        return TEMPLATES;
    }

    /**
     * 设置模板变量信息
     *
     * @param genTable
     * @param columns
     * @return {@link VelocityContext}
     */
    public VelocityContext prepareContext(GenTable genTable, List<GenTableColumn> columns) {
        String businessName = genTable.getBusinessName();
        String functionName = genTable.getFunctionName();

        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("tplCategory", genTable.getTplCategory());
        velocityContext.put("tableName", genTable.getTableName());
        velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
        velocityContext.put("ClassName", genTable.getClassName());
        velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
        velocityContext.put("moduleName", genTable.getModuleName());
        velocityContext.put("BusinessName", StringUtils.capitalize(businessName));
        velocityContext.put("businessName", businessName);
        velocityContext.put("basePackage", buildPackagePrefix(genTable.getPackageName()));
        velocityContext.put("packageName", genTable.getPackageName());
        velocityContext.put("author", genTable.getFunctionAuthor());
        velocityContext.put("datetime", LocalDate.now());
        velocityContext.put("importList", buildImportList(columns));
        velocityContext.put("reqImportList", buildReqImportList(columns));
        velocityContext.put("rspImportList", buildRspImportList(columns));
        velocityContext.put("permissionPrefix", StrUtil.format("{}:{}", genTable.getModuleName(), businessName));
        velocityContext.put("columns", columns);
        velocityContext.put("table", genTable);
        setMenuVelocityContext(velocityContext, genTable);
        return velocityContext;
    }

    private Set<String> buildRspImportList(List<GenTableColumn> columns) {
        List<GenTableColumn> tableColumns = StreamUtil.filter(columns, column ->
                GenConstants.REQUIRE.equals(column.getIsList()));
        return buildImportList(tableColumns);
    }

    private void setMenuVelocityContext(VelocityContext context, GenTable genTable) {
        String options = genTable.getOptions();
        Dict paramsObj = JSON.parseObject(options, Dict.class);
        String parentMenuId = getParentMenuId(paramsObj);
        context.put("parentMenuId", parentMenuId);
    }

    /**
     * 获取上级菜单ID字段
     *
     * @param paramsObj 生成其他选项
     * @return 上级菜单ID字段
     */
    private String getParentMenuId(Dict paramsObj) {
        if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
                && StringUtils.isNotEmpty(paramsObj.getStr(GenConstants.PARENT_MENU_ID))) {
            return paramsObj.getStr(GenConstants.PARENT_MENU_ID);
        }
        return MoneyTrackerConstant.DEFAULT_PARENT_MENU_ID;
    }


    /**
     *
     * 构造入参需要导入的包
     *
     * @param columns
     * @return {@link Set}<{@link String}>
     */
    private Set<String> buildReqImportList(List<GenTableColumn> columns) {
        List<GenTableColumn> tableColumns = StreamUtil.filter(columns, column ->
                GenConstants.REQUIRE.equals(column.getIsQuery()) || GenConstants.REQUIRE.equals(column.getIsInsert())
                        || GenConstants.REQUIRE.equals(column.getIsRequired()));
        return buildImportList(tableColumns);
    }

    /**
     * 根据列类型获取导入包
     *
     * @param columns
     * @return 返回需要导入的包列表
     */
    private Set<String> buildImportList(List<GenTableColumn> columns) {
        Set<String> importList = new HashSet<>();
        for (GenTableColumn column : columns) {
            if (StringUtils.equalsIgnoreCase(GenConstants.TYPE_DATE, column.getJavaType())) {
                importList.add("java.util.Date");
                importList.add("com.fasterxml.jackson.annotation.JsonFormat");
                continue;
            }
            if (StringUtils.equalsIgnoreCase(GenConstants.TYPE_BIGDECIMAL, column.getJavaType())) {
                importList.add("java.math.BigDecimal");
                continue;
            }
            if (StringUtils.equalsIgnoreCase(column.getJavaType(), GenConstants.TYPE_LOCAL_DATE_TIME)) {
                importList.add("java.time.LocalDateTime");
            }
        }
        return importList;
    }

    /**
     * 获取包前缀
     *
     * @param packageName 包名称
     * @return 包前缀名称
     */
    private String buildPackagePrefix(String packageName) {
        int lastIndex = packageName.lastIndexOf(".");
        return StringUtils.substring(packageName, 0, lastIndex);
    }

}
